home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
gnu
/
gas
/
gassrc04.zoo
/
vms-dbg.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-24
|
38KB
|
1,126 lines
#include <stdio.h>
#include "as.h"
#include "struc-symbol.h"
#include "symbols.h"
#include "objrecdef.h"
#include <stab.h>
/* This file contains many of the routines needed to output debugging info into
* the object file that the VMS debugger needs to understand symbols. These
* routines are called very late in the assembly process, and thus we can be
* fairly lax about changing things, since the GSD and the TIR sections have
* already been output.
*/
/* We need this info to cross correlate between the stabs def for a symbol and
* the actual symbol def. The actual symbol def contains the psect number and
* offset, which is needed to declare a variable to the debugger for global
* and static variables
*/
struct VMS_Symbol {
struct VMS_Symbol *Next;
struct symbol *Symbol;
int Size;
int Psect_Index;
int Psect_Offset;
};
extern struct VMS_Symbol *VMS_Symbols;
enum advanced_type {BASIC,POINTER,ARRAY,ENUM,STRUCT,UNION,FUNCTION,VOID,UNKNOWN};
/* this structure contains the information from the stabs directives, and the
* information is filled in by VMS_typedef_parse. Everything that is needed
* to generate the debugging record for a given symbol is present here.
* This could be done more efficiently, using nested struct/unions, but for now
* I am happy that it works.
*/
struct VMS_DBG_Symbol{
struct VMS_DBG_Symbol * next;
enum advanced_type advanced; /* description of what this is */
int dbx_type; /* this record is for this type */
int type2; /* For advanced types this is the type referred to.
i.e. the type a pointer points to, or the type
of object that makes up an array */
int VMS_type; /* Use this type when generating a variable def */
int index_min; /* used for arrays - this will be present for all */
int index_max; /* entries, but will be meaningless for non-arrays */
int data_size; /* size in bytes of the data type. For an array, this
is the size of one element in the array */
int struc_numb; /* Number of the structure/union/enum - used for ref */
};
struct VMS_DBG_Symbol *VMS_Symbol_type_list={(struct VMS_DBG_Symbol*) NULL};
/* we need this structure to keep track of forward references to
* struct/union/enum that have not been defined yet. When they are ultimately
* defined, then we can go back and generate the TIR commands to make a back
* reference.
*/
struct forward_ref{
struct forward_ref * next;
int dbx_type;
int struc_numb;
char resolved;
};
struct forward_ref * f_ref_root={(struct forward_ref*) NULL};
static char * symbol_name;
static structure_count=0;
/* this routine converts a number string into an integer, and stops when it
* sees an invalid character the return value is the address of the character
* just past the last character read. No error is generated.
*/
static char * cvt_integer(char* str,int * rtn){
int ival, neg;
neg = *str == '-' ? ++str, -1 : 1;
ival=0; /* first get the number of the type for dbx */
while((*str <= '9') && (*str >= '0'))
ival = 10*ival + *str++ -'0';
*rtn = neg*ival;
return str;
}
/* this routine fixes the names that are generated by C++, ".this" is a good
* example. The period does not work for the debugger, since it looks like
* the syntax for a structure element, and thus it gets mightily confused
*/
static fix_name(char* pnt){
for( ;*pnt != 0; pnt++){
if(*pnt == '.') *pnt = '$';
};
}
/* this routine is used to compare the names of certain types to various
* fixed types that are known by the debugger.
*/
#define type_check(x) !strcmp( symbol_name , x )
/* When defining a structure, this routine is called to find the name of
* the actual structure. It is assumed that str points to the equal sign
* in the definition, and it moves backward until it finds the start of the
* name. If it finds a 0, then it knows that this structure def is in the
* outermost level, and thus symbol_name points to the symbol name.
*/
static char* get_struct_name(char* str){
char* pnt;
pnt=str;
while((*pnt != ':') && (*pnt != '\0')) pnt--;
if(*pnt == '\0') return symbol_name;
*pnt-- = '\0';
while((*pnt != ';') && (*pnt != '=')) pnt--;
if(*pnt == ';') return pnt+1;
while((*pnt < '0') || (*pnt > '9')) pnt++;
while((*pnt >= '0') && (*pnt <= '9')) pnt++;
return pnt;
}
/* search symbol list for type number dbx_type. Return a pointer to struct */
static struct VMS_DBG_Symbol* find_symbol(int dbx_type){
struct VMS_DBG_Symbol* spnt;
spnt=VMS_Symbol_type_list;
while (spnt!=(struct VMS_DBG_Symbol*) NULL){
if(spnt->dbx_type==dbx_type) break;
spnt=spnt->next;};
if(spnt==(struct VMS_DBG_Symbol*) NULL) return 0;/*Dunno what this is*/
return spnt;
}
/* Many good programmers cringe when they see a fixed size array - since I am
* using this to generate the various descriptors for the data types present,
* you might argue that the descriptor could overflow the array for a
* complicated variable, and then I am in deep doo-doo. My answer to this is
* that the debugger records that we write have all sorts of length bytes
* stored in them all over the place, and if we exceed 127 bytes (since the top
* bit indicates data, rather than a command), we are dead anyhow. So I figure
* why not do this the easy way. Besides, to get 128 bytes, you need something
* like an array with 10 indicies, or something like
* char **************************************** var;
* Lets get real. If some idiot writes programs like that he/she gets what
* they deserve. (It is possible to overflow the record with a somewhat
* simpler example, like: int (*(*(*(*(*(* sarr6)[1])[1])[2])[3])[4])[5];
* but still...). And if someone in the peanut gallery wants to know "What
* does VAX-C do with something like this?", I will tell you. It crashes.
* At least this code has the good sense to convert it to *void.
* In practice, I do not think that this presents too much of a problem, since
* struct/union/enum all use defined types, which sort of terminate the
* definition. It occurs to me that we could possibly do the same thing with
* arrays and pointers, but I don't know quite how it would be coded.
*
* And now back to the regularly scheduled program...
*/
#define MAX_DEBUG_RECORD 128
static char Local[MAX_DEBUG_RECORD]; /* buffer for variable descriptor */
static int Lpnt; /* index into Local */
static char Asuffix[MAX_DEBUG_RECORD]; /* buffer for array descriptor */
static int Apoint; /* index into Asuffix */
static char overflow; /* flag to indicate we have written too much*/
static int total_len; /* used to calculate the total length of variable
descriptor plus array descriptor - used for len byte*/
static int struct_number; /* counter used to assign indexes to struct
unions and enums */
/* this routine puts info into either Local or Asuffix, depending on the sign
* of size. The reason is that it is easier to build the variable descriptor
* backwards, while the array descriptor is best built forwards. In the end
* they get put together, if there is not a struct/union/enum along the way
*/
push(int value, int size){
char * pnt;
int i;
int size1;
long int val;
val=value;
pnt=(char*) &val;
size1 = size;
if (size < 0) {size1 = -size; pnt += size1-1;};
if(size < 0)
for(i=0;i<size1;i++) {
Local[Lpnt--] = *pnt--;
if(Lpnt < 0) {overflow = 1; Lpnt = 1;};}
else for(i=0;i<size1;i++){
Asuffix[Apoint++] = *pnt++;
if(Apoint >= MAX_DEBUG_RECORD)
{overflow = 1; Apoint =MAX_DEBUG_RECORD-1;};}
}
/* this routine generates the array descriptor for a given array */
static array_suffix(struct VMS_DBG_Symbol* spnt2){
struct VMS_DBG_Symbol * spnt;
struct VMS_DBG_Symbol * spnt1;
int rank;
int total_size;
int i;
rank=0;
spnt=spnt2;
while(spnt->advanced != ARRAY) {
spnt=find_symbol(spnt->type2);
if(spnt == (struct VMS_DBG_Symbol *) NULL) return;};
spnt1=spnt;
spnt1=spnt;
total_size= 1;
while(spnt1->advanced == ARRAY) {rank++;
total_size *= (spnt1->index_max - spnt1->index_min +1);
spnt1=find_symbol(spnt1->type2);};
total_size = total_size * spnt1->data_size;
push(spnt1->data_size,2);
if(spnt1->VMS_type == 0xa3) push(0,1);
else push(spnt1->VMS_type,1);
push(4,1);
for(i=0;i